package com.tbit.uqbike.client.controller;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.tbit.uqbike.center.pojo.MachineStatus;
import com.tbit.uqbike.client.constant.*;
import com.tbit.uqbike.client.exception.BaseException;
import com.tbit.uqbike.client.pojo.*;
import com.tbit.uqbike.client.service.*;
import com.tbit.uqbike.client.service.impl.ParkPointInfo;
import com.tbit.uqbike.client.util.Assert;
import com.tbit.uqbike.client.util.ObjectUtil;
import com.tbit.uqbike.client.util.OutputUtil;
import com.tbit.uqbike.client.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 停车点
 *
 * @author Leon
 * 2017年2月24日 下午5:51:05
 */
@Controller
@RequestMapping("/parkPoint")
@Slf4j
public class ParkPointController {
    @Autowired
    private ParkPointService parkPointService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private CalibrateService calibrateService;
    @Autowired
    private MachineService machineService;
    @Autowired
    private GeoService geoService;
    @Autowired
    private MachineStatusService machineStatusService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private TerControlService terControlService;
    @Autowired
    private ParkPointVertService parkPointVertService;
    @Autowired
    private ProhibitAreaService prohibitAreaService;
    @Autowired
    private MachineBorrowService machineBorrowService;
    @Autowired
    private ParkMachineService parkMachineService;

    /**
     * 查询附近停车点数据
     *
     * @param token    令牌
     * @param lo       经度
     * @param la       纬度
     * @param radius   半径
     */
    @RequestMapping("/getByArea")
    public Result<List<ParkPoint>> getByArea(String token, Double lo, Double la, Integer radius) {
        // 这个接口目前前端没用到
        User user = tokenService.getUser(token);

        Assert.notNull(lo, "-2001", "经度不能为空");
        Assert.notNull(la, "-2002", "纬度不能为空");

        return Result.success(
                parkPointService.getByArea(user.getAccountId(), lo, la, radius)
        );
    }


    /**
     * 查询周边停车点数据 正在使用
     *
     * @param token          令牌
     * @param userCode       车辆编号
     * @param accountId      品牌id
     * @param lo             经度
     * @param la             纬度
     * @param adAccountId    区域id
     * @param radius         半径，不传则获取配置值
     * @param prohibitRadius 禁停区查询半径，不传则获取配置值
     * @param mapType        地图类型
     * @ignoreParams request
     */
    @RequestMapping("/getNear")
    public void getNear(String token, String userCode, Integer accountId, Double lo, Double la, Integer adAccountId,
                        Integer radius, Integer mapType, Integer prohibitRadius, HttpServletRequest request, HttpServletResponse response) {
        Map<String, Object> map = new HashMap<>();

        try {
            Assert.notNull(accountId, "-10001", "平台id不能为空");
            Assert.notNull(lo, "-2001", "经度不能为空");
            Assert.notNull(la, "-2002", "纬度不能为空");
//            Assert.notNull(radius, "-2003", "半径不能为空");

            /*校准百度经纬度为原始经纬度*/
            Point point = new Point(lo, la);

            if (mapType == null) {
                mapType = MapConstant.MAP_GOOGLE;
            }

            /**校准成原始经纬度*/
            point = calibrateService.calibrate(point, mapType, SysConstant.ORIGINAL);

            User user = null;
            if (token != null) {
                user = tokenService.getUser(token);
            }
            Integer agentId = null;
//            Integer agentId = geoService.getBelongAccount(accountId, lo, la, mapType);
//            if (agentId == null) {
//                agentId = accountId;
//            }
//            if (adAccountId != null) {
//                agentId = adAccountId;
//            }
            Boolean temp = false;
            /**用户有借车，暂时当前借车区域站点*/
            if (user != null) {
                MachineBorrow machineBorrow = machineBorrowService.getByUserId(user.getUserId());
                if (machineBorrow != null) {
                    Machine machine = machineService.getByMachineId(machineBorrow.getMachineId());
                    agentId = machine.getAccountId();
                    temp = true;
                }
            }
            if (!temp) {
                if (adAccountId != null) {
                    agentId = adAccountId;
                } else {
                    agentId = geoService.getBelongAccount(accountId, lo, la, mapType);
                    if (agentId == null) {
                        agentId = accountId;
                    }
                }
            }

            List<ParkPoint> parkPoints = parkPointService.getNearParkPoint(user, agentId, point.getX(), point.getY(), radius, mapType);
            if (parkPoints.size() > 0) {
                List<Integer> collect = parkPoints.stream().map(ParkPoint::getParkPointId).collect(Collectors.toList());
                List<Map<String, Object>> parkPointCanBorrowNums = new ArrayList<>();
                if (collect.size() > 1000) {
                    List<List<Integer>> limits = Lists.partition(collect, 1000);
                    for (List<Integer> parkPointIds : limits) {
                        parkPointCanBorrowNums.addAll(parkMachineService.getParkPointCanBorrowNums(parkPointIds));
                    }
                } else {
                        parkPointCanBorrowNums = parkMachineService.getParkPointCanBorrowNums(collect);
                }
                Map<Integer, Integer> parkPoinCount = parkPointCanBorrowNums.stream().collect(Collectors.toMap(e -> Integer.valueOf(e.get("parkPointId").toString()), e -> Integer.valueOf(e.get("canBorrowNum").toString()), (k1, k2) -> k1));
                parkPoints.forEach(p -> {
                    if (p.getCapacity() > 0 && parkPoinCount.getOrDefault(p.getParkPointId(),0) >= p.getCapacity()) {
                        p.setOverflow(1);
                    } else {
                        p.setOverflow(0);
                    }
                });
            }
            //List<Integer> ids = new ArrayList<>();
//            if (parkPoints.size() > 0) {
//                for (ParkPoint p : parkPoints) {
//                    ids.add(p.getParkPointId());
//                    // 3.1.2优化：用户借车以后，满桩站点使用不同的图标展示：1：站点满桩，0：站点未满
//                    Integer count = parkMachineService.getParkPointCanBorrowNum(p.getParkPointId());
//                    if (p.getCapacity() > 0 && count >= p.getCapacity()) {
//                        p.setOverflow(1);
//                    } else {
//                        p.setOverflow(0);
//                    }
//                }
//            }
            /**添加垂直停车配置信息*/
            if (parkPoints.size() > 0) {
                if (userCode != null) {
                    Machine machine = machineService.getByUserCode(userCode);
                    ParkPointInfo parkPointInfo = machineService.isInParkPoint(agentId, machine.getMachineNO(), point, mapType);
                    Integer parkPointId = parkPointInfo.getParkPointId();
                    if (parkPointId != null) {
                        ParkPointVert vert = parkPointVertService.getByParkPointId(parkPointId);
                        if (vert != null) {
                            vert.setPointsC(calibrateService.calVert(vert.getPoints(), MapConstant.MAP_ORI,
                                    MapConstant.MAP_GOOGLE));
                            double parkAngle = machineService.getParkAngle(vert.getPoints());
                            vert.setAngle(parkAngle);
                            map.put("vert", vert);
                        }
                    }
                }
            }
            List<ProhibitArea> list;
            if (prohibitRadius == null) {
                list = prohibitAreaService.getByArea(agentId, point.getX(), point.getY());
            } else {
                list = prohibitAreaService.getByAreaAndRadius(agentId, point.getX(), point.getY(), prohibitRadius);
            }
            /**站点模式兼容返回禁停区*/
            if (!list.isEmpty()) {
                calibrateService.celibrateProhibit(list, mapType);
                map.put("prohibitArea", list);
            }

            map.put(ResponseCode.RET, ResponseCode.SUCC);
            map.put(ResponseCode.DATA, parkPoints);
        } catch (BaseException e) {
            ResponseCode.printException(map, e, request);
        }

        OutputUtil.renderText(request, response, map);
    }


    /**
     * 查询周边停车点数据
     *
     * @param token     令牌
     * @param accountId 品牌id
     * @param lo        经度
     * @param la        纬度
     * @param radius    半径
     * @param mapType   地图类型
     * @param session   会话
     * @param response  响应
     * @ignoreParams request
     */
    @RequestMapping("/getNearPark")
    public void getNearPark(String token, Integer accountId, Double lo, Double la, Integer radius, Integer mapType,
                            HttpSession session, HttpServletRequest request, HttpServletResponse response) {
        // 这个接口目前前端没用到
        Map<String, Object> map = new HashMap<String, Object>();

        try {
            Assert.notNull(accountId, "-10001", "平台id不能为空");
            Assert.notNull(lo, "-2001", "经度不能为空");
            Assert.notNull(la, "-2002", "纬度不能为空");
            Assert.notNull(radius, "-2003", "半径不能为空");

            if (mapType == null) {
                mapType = MapConstant.MAP_BAIDU;
            }

            /*校准百度经纬度为原始经纬度*/
            Point point = new Point(lo, la);
            point = calibrateService.calibrate(point, mapType, SysConstant.ORIGINAL);

            User user = null;
            if (token != null) {
                user = tokenService.getUser(token);
            }

            List<ParkPoint> parkPoints = parkPointService.getNearParkPoint(user, accountId, point.getX(), point.getY(), radius, mapType);

            map.put(ResponseCode.RET, ResponseCode.SUCC);
            map.put(ResponseCode.DATA, parkPoints);
        } catch (BaseException e) {
            ResponseCode.printException(map, e, request);
        }

        OutputUtil.renderText(request, response, map);
    }


    /**
     * 查询停车点内车辆数据
     *
     * @param token       令牌
     * @param parkPointId 站点id
     * @param session     会话
     * @param response    响应
     * @ignoreParams request
     */
    @RequestMapping("/getByParkPointId")
    public void getByParkPointId(String token, Integer parkPointId, HttpSession session,
                                 HttpServletRequest request, HttpServletResponse response) {
        Map<String, Object> map = new HashMap<String, Object>();

        try {
            Assert.notNull(parkPointId, "-40001", "parkPointId不能为空");

            List<MachineStatus> machineStatuses = parkPointService.getStatusByParkPoint(parkPointId);

            map.put(ResponseCode.RET, ResponseCode.SUCC);
            map.put(ResponseCode.DATA, machineStatuses);
        } catch (BaseException e) {
            ResponseCode.printException(map, e, request);
        }

        OutputUtil.renderText(request, response, map);
    }


    /**
     * 查询停车点信息
     *
     * @param token       令牌
     * @param parkPointId 停车点id
     * @param session     会话
     * @param response    响应
     * @ignoreParams request
     */
    @RequestMapping("/getInfoByParkPointId")
    public void getInfoByParkPointId(String token, Integer parkPointId, HttpSession session,
                                     HttpServletRequest request, HttpServletResponse response) {
        Map<String, Object> map = new HashMap<String, Object>();

        try {
            Assert.notNull(parkPointId, "-40001", "parkPointId不能为空");

            ParkPoint parkPoint = parkPointService.getByParkPointId(parkPointId);

            /**校准经纬度*/
            calibrateService.celibrateParkPoint(parkPoint, MapConstant.MAP_BAIDU);

            map.put(ResponseCode.RET, ResponseCode.SUCC);
            map.put(ResponseCode.DATA, parkPoint);
        } catch (BaseException e) {
            ResponseCode.printException(map, e, request);
        }

        OutputUtil.renderText(request, response, map);
    }


    /**
     * 检查是否在停车点
     *
     * @param token     令牌
     * @param machineNO 设备编号
     * @param lo        经度
     * @param la        纬度
     * @param isBaidu   是百度地图
     * @param session   会话
     * @param response  响应
     * @ignoreParams request
     */
    @RequestMapping("/checkInParkPoint")
    public void checkInParkPoint(String token, String machineNO, Double lo, Double la, Boolean isBaidu,
                                 HttpSession session, HttpServletRequest request, HttpServletResponse response) {
        Map<String, Object> map = new HashMap<String, Object>();

        try {
            Assert.hasLength(machineNO, "-30001", "machineNO不能为空");
            Assert.notNull(lo, "-2001", "经度不能为空");
            Assert.notNull(la, "-2002", "纬度不能为空");

            /**查询指定设备存在不存在*/
            Machine machine = machineService.getByMachineNO(machineNO);
            if (machine == null) {
                throw new BaseException("-30005", "该编号不存在");
            }

            /*校准百度经纬度为原始经纬度*/
            Point point = new Point(lo, la);
            if (isBaidu != null && isBaidu) {
                point = calibrateService.calibrate(point, SysConstant.BAIDU, SysConstant.ORIGINAL);
            }
            log.info("站点检测：lo :" + lo + ",la :" + la + "校准后经纬度：" + "lo :" + point.getX() + ",la:" + point.getY());

            ParkPointInfo parkPointInfo = machineService.isInParkPoint(machine.getAccountId(), machine.getMachineNO(), point,
                    MapConstant.MAP_GOOGLE);
            Integer parkPointId = parkPointInfo.getParkPointId();
            map.put(ResponseCode.RET, ResponseCode.SUCC);
            map.put(ResponseCode.DATA, parkPointId == null ? false : true);
        } catch (BaseException e) {
            ResponseCode.printException(map, e, request);
        }

        OutputUtil.renderText(request, response, map);
    }

    /**
     * 获取最近停车点
     *
     * @param token     令牌
     * @param accountId 品牌id
     * @param lo        经度
     * @param la        纬度
     * @param mapType   地图类型
     * @param session   会话
     * @param response  响应
     * @ignoreParams request
     */
    @RequestMapping("/getPark")
    public void getPark(String token, Integer accountId, Double lo, Double la, Integer mapType,
                        HttpSession session, HttpServletRequest request, HttpServletResponse response) {
        Map<String, Object> map = new HashMap<String, Object>();

        try {
            Assert.notNull(accountId, "-10001", "平台id不能为空");
            Assert.notNull(lo, "-2001", "经度不能为空");
            Assert.notNull(la, "-2002", "纬度不能为空");
            /*校准百度经纬度为原始经纬度*/
            Point point = new Point(lo, la);

            if (mapType == null) {
                mapType = MapConstant.MAP_GOOGLE;
            }
            // todo 添加adAccountId
            /**校准成原始经纬度*/
            point = calibrateService.calibrate(point, mapType, SysConstant.ORIGINAL);

            Integer agentId = geoService.getBelongAccount(accountId, lo, la, mapType);
            if (agentId == null) {
                agentId = accountId;
            }
            ParkPoint parkPoints = parkPointService.getPark(agentId, point, mapType);
            if (parkPoints == null) {
                throw new BaseException("-160007", "附近无可用站点");
            }
            map.put(ResponseCode.RET, ResponseCode.SUCC);
            map.put(ResponseCode.DATA, parkPoints);
        } catch (BaseException e) {
            ResponseCode.printException(map, e, request);
        }

        OutputUtil.renderText(request, response, map);
    }

    /**
     * 获取垂直停车数据
     *
     * @param userCode 车辆编号
     * @param type     1、垂直停车。2、道钉。*3、头盔锁。4、脚撑。5、位置、电量。
     * @param session  会话
     * @param response 响应
     * @ignoreParams request
     */
    @RequestMapping("/getVert")
    public void getVert(String userCode, @RequestParam(defaultValue = "1") Integer type, Integer parkPointId, Double lon, Double lat,
                        HttpSession session, HttpServletRequest request, HttpServletResponse response) {
        Map<String, Object> map = new HashMap<String, Object>();

        try {
            Assert.notNull(userCode, "-30006", "用户码不能为空");
            Machine machine = machineService.getByUserCode(userCode);
            if (machine == null) {
                throw new BaseException("-30005", "设备不存在");
            }
            if (type == 1) {
                ParkPointVo parkPointVo = parkPointService.getVert(userCode, parkPointId, lon, lat);
                map.put(ResponseCode.DATA, parkPointVo);
            } else if (type == 2) {
                //BleInfo bleInfo= SystemData.bleInfoMap.get(machine.getMachineNO());
                String tmp = redisService.get(RedisConstant.MACHINE_NO_BLEINFO + machine.getMachineNO());
                List<BleInfo> list = new ArrayList<>();
                if (tmp != null) {
                    list = JSON.parseArray(tmp, BleInfo.class);
                }
                map.put(ResponseCode.DATA, list);
            } else if (type == 3) {
                String json = redisService.getMain(
                        RedisUtil.getTerHashId(machine.getMachineNO()), RedisConstant.REDIS_TER_LAST_STATUS);
                if (json != null && json.length() > 0) {
                    TerLastStatus terLastStatus = JSON.parseObject(json, TerLastStatus.class);
                    Integer terStatus = terLastStatus.getCarStatus();
                    map.put(ResponseCode.DATA, ObjectUtil.statusParse(11, terStatus));
                } else {
                    map.put(ResponseCode.DATA, false);
                }
            } else if (type == 4) {

            } else if (type == 5) {
                MachineStatus machineStatus = machineStatusService.getByMachineNO(machine.getMachineNO(),
                        MapConstant.MAP_GOOGLE);
                map.put(ResponseCode.DATA, machineStatus);
            }

            map.put(ResponseCode.RET, ResponseCode.SUCC);

        } catch (BaseException e) {
            ResponseCode.printException(map, e, request);
        }

        OutputUtil.renderText(request, response, map);
    }

    /**
     * 下发指令刷新状态
     *
     * @param userCode
     * @param type     1、垂直停车。2、道钉。*3、头盔锁。4、脚撑。5、RFID。 6 NFC。7 高精度
     * @param session
     * @param request
     * @param response
     * @ignore
     */
    @RequestMapping("/refresh")
    public void refresh(String userCode, @RequestParam(defaultValue = "1") Integer type,
                        HttpSession session, HttpServletRequest request, HttpServletResponse response) {
        Map<String, Object> map = new HashMap<String, Object>();

        try {
            Assert.notNull(userCode, "-30006", "用户码不能为空");
            Machine machine = machineService.getByUserCode(userCode);
            if (machine == null) {
                throw new BaseException("-30005", "设备不存在");
            }
            if (type == 1) {
                String serNO = UUID.randomUUID().toString();
                int i = 0x37;
                terControlService.sendControl(serNO, machine.getMachineNO(), ControlTypeConstant.CONTROL_TYPE_CONTROL, String.valueOf(i), "", null, true, -1, null, "");
            } else if (type == 2) {
                String serNO = UUID.randomUUID().toString();
                terControlService.sendControl(serNO, machine.getMachineNO(), ControlTypeConstant.CONTROL_TYPE_CONTROL, "51", "", null, true, -1, null, "");
            } else if (type == 3) {

            } else if (type == 4) {

            } else if (type == 5) {

            }
            map.put(ResponseCode.RET, ResponseCode.SUCC);
        } catch (BaseException e) {
            ResponseCode.printException(map, e, request);
        }

        OutputUtil.renderText(request, response, map);
    }
}